package sudoku;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSlider;

/**
 * Class holding main frame of the game. There is game canvas, solution panel 
 * and menu currently on this frame.  
 * @author Taras Basiuk
 * @version 0.1
 */
public class MainFrame extends JFrame{
    
    private ClassicGrid grid;
    private ClassicCanvas canvas;
    private ClassicGridSolutionPanel solPanel;
    private MainFrame thisFrame;
    private JMenuBar bar;
    
    public MainFrame(int level, int emptyCellsPercentage){
        
        super("Sudoku");
        thisFrame = this; /** @todo Should i worry about this ?! */
        setLayout(new BorderLayout());
        grid = ClassicGrid.makeSolvableGrid(level, emptyCellsPercentage);
        canvas = new ClassicCanvas(this);
        solPanel = new ClassicGridSolutionPanel(this);
        add(solPanel, BorderLayout.WEST);
        add(canvas, BorderLayout.CENTER);        
        
        bar = new JMenuBar();
        JMenu menu = new JMenu("Menu"); 
        menu.setMnemonic(KeyEvent.VK_M);
        
         // NewGame menu item creates custom dialog window where user specifies
         // type level, and percentage of empty cells of new sudoku grid. Then
         // specified sudoku game being created.
        JMenuItem newGame = new JMenuItem("New game", KeyEvent.VK_N);
        newGame.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                
                final JFrame frm = new JFrame("Choose sudoku"); // custom dialog window  
                //initial layout setup
                JPanel panel = new JPanel();
                GroupLayout layout = new GroupLayout(panel);
                layout.setAutoCreateGaps(true);
                panel.setLayout(layout);
                //labels setup
                JLabel label1 = new JLabel("Type of sudoku :");
                label1.setPreferredSize(new Dimension(110,20));
                JLabel label2 = new JLabel("Sudoku level :");
                label2.setPreferredSize(new Dimension(110,20));
                JLabel label3 = new JLabel("Empty cells % :");
                label3.setPreferredSize(new Dimension(110,20));
                // combobox setups
                final JComboBox comboBox1 = new JComboBox();
                comboBox1.setPreferredSize(new Dimension(150,20));
                comboBox1.addItem("Classic sudoku");
                
                final JComboBox comboBox2 = new JComboBox();
                comboBox2.setPreferredSize(new Dimension(150,20));
                comboBox2.addItem("9x9");
                comboBox2.addItem("16x16");
                // slider setup
                final JSlider slider = new JSlider(20, 100, 50);
                slider.setMajorTickSpacing(10);
                slider.setFont(new Font(Font.SERIF, 0, 10));
                slider.setPaintLabels(true);
                slider.setPreferredSize(new Dimension(150,25));
                slider.setSnapToTicks(true);
                // ok button setup
                JButton okButton = new JButton("OK");
                okButton.setPreferredSize(new Dimension(100, 20));
                okButton.addActionListener(new ActionListener(){
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        thisFrame.setEnabled(true);                          
                        frm.dispose();  
                        // update thisFrame with new canvas and solution panel
                        thisFrame.grid = ClassicGrid.makeSolvableGrid(comboBox2.getSelectedIndex()+3, slider.getValue());
                        thisFrame.remove(canvas);                        
                        thisFrame.canvas = new ClassicCanvas(thisFrame);
                        thisFrame.add(canvas, BorderLayout.CENTER);
                        thisFrame.updateSolutionPanel();
                    }
                });
                // cancel button setup
                JButton cancelButton = new JButton("Cancel");
                cancelButton.setPreferredSize(new Dimension(100, 20));
                cancelButton.addActionListener(new ActionListener(){
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        thisFrame.setEnabled(true);
                        frm.dispose();
                    }
                });
                // horizontal setup
                layout.setHorizontalGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER)
                            .addComponent(label1, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                            .addComponent(label2, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                            .addComponent(label3, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                            .addComponent(okButton, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                        )
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER)
                            .addComponent(comboBox1, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                            .addComponent(comboBox2, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                            .addComponent(slider, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                            .addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                        )
                );
                // vertical setup
                layout.setVerticalGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                            .addComponent(label1, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                            .addComponent(comboBox1, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                        )
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                            .addComponent(label2, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                            .addComponent(comboBox2, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                        )
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                            .addComponent(label3, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                            .addComponent(slider, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                        )
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER)
                            .addComponent(okButton, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                            .addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
                        )
                );
                
                panel.setPreferredSize(new Dimension(280, 135));                
                              
                frm.add(panel);
                frm.setSize(panel.getPreferredSize());
                
                frm.setLocation(thisFrame.getLocation().x + thisFrame.getSize().width/2 - panel.getPreferredSize().width/2, 
                        thisFrame.getLocation().y + thisFrame.getSize().height/2 - panel.getPreferredSize().height/2);
                frm.setVisible(true);
                frm.setResizable(false);
                frm.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
                thisFrame.setEnabled(false);
            }
        });
        
        // Quit menuitem setup
        JMenuItem quit = new JMenuItem("Quit", KeyEvent.VK_Q);               
        quit.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {                
                thisFrame.setVisible(false);
                thisFrame.dispose();
            }
        });
        
        menu.add(newGame);
        menu.add(quit);
        bar.add(menu);
        setJMenuBar(bar);
        
        pack();
        //create new game frame at the center of the screen
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); 
        setLocation(dim.width/2 - getSize().width/2, dim.height/2 - getSize().height/2);
        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        setVisible(true); 
    }
    
    /** Returns a copy of grid associated with this frame canvas. */
    public ClassicGrid getGridCopy(){
        return grid.clone();
    }
    
    /** Repaints canvas. */
    public void updateCanvas(){
        canvas.repaint();        
    }
    
    /** 
     * Performs insertion of given value to this frame original sudoku grid.
     * @param rowN Cell row number in the grid
     * @param value Value to insert to chosen cell
     * @param update Indicates whether there is a need to update solPanel now 
     */
    public boolean insertToGrid(int rowN, int value, boolean update){
        boolean success = grid.userInsertValue(rowN, value);
        if (success && update) {            
            updateSolutionPanel();
        }        
        return success;
    }
    
    /** 
     * Performs erasure from this frame original sudoku grid.
     * @param rowN Cell row number in the grid
     * @param update Indicates whether there is a need to update solPanel now 
     */
    public boolean eraseFromGrid(int rowN, boolean update){
        boolean success = grid.userEraseValue(rowN);
        if (success && update) {            
            updateSolutionPanel();
        }
        return success;
    }
    
    /** Replaces solPanel with new one. Finishes threads running in previous solPanel. */
    public void updateSolutionPanel(){
        boolean expanded = solPanel.isExpanded();
        solPanel.finish();
        remove(solPanel);
        solPanel = new ClassicGridSolutionPanel(this, expanded);
        add(solPanel, BorderLayout.WEST);
        pack();
    }
    
    /** Method used to draw solution of this frame canvas, don't have any element except canvas on a frame.*/
    public static void drawCanvas(ClassicGrid grid){
        MainFrame frame = new MainFrame(grid.getLevel(), 0);
        frame.grid = grid;
        frame.remove(frame.solPanel);
        frame.bar.setVisible(false);
        //frame.remove(frame.bar); Doesn't work !!!
        frame.canvas.removeMouseMotionListener(frame.canvas.getMouseMotionListeners()[0]);
        frame.pack();
        frame.setTitle("Solution");
        frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
    }
    
    /** Main method. */
    public static void main(String[] args){
        
        MainFrame frame = new MainFrame(3, 50); 
        
    }
}
    


